July 27, 2020
def parent_function():
def child_function():
print("this is a child function")
child_function()
parent_function()
"this is a child function"
def print_all_elements(list_of_things):
# 중첩함수 선언
def print_each_element(things):
for thing in things:
print(thing)
if len(list_of_things) > 0:
print_each_element(list_of_things)
else:
print("There is nothing!")
💡Closure는 언제 사용 할까?
주로 Factory 패턴을 구현할 때 사용
💡Factory?
2의 승을 구하는 함수를 구현한다면 다음과 같은 코드로 작성이 가능할 것이다.
def calculate_power_of_two(power):
return 2 ** power
calculate_power_of_two(7)
-> 128
calculate_power_of_two(10)
-> 1024
하지만 위 함수는 2의 승밖에 구할 수 없다. 따라서 만일, 특정 숫자의 승을 구하는 함수가 필요 하지만 2가 아니라 설정되는 수의 승을 구하는 함수는 Closure를 사용하여 다음과 같이 구현할 수 있다.
def generate_power(base_number):
def nth_power(power):
return base_number ** power
return nth_power
calculate_power_of_two = generate_power(2)
calculate_power_of_two(7)
-> 128
calculate_power_of_two(10)
-> 1024
calculate_power_of_seven = generate_power(7)
calculate_power_of_seven(3)
-> 343
calculate_power_of_seven(5)
-> 16907
Decorator가 있는 함수의 실행 순서
Decorator가 존재하는 함수
💡Decorator가 존재하는 함수는 무조건 Decorator가 먼저 선 호출 된다.
Decorator는 Chain of Function, 즉 여러개의 함수가 연속적으로 호출되어야 하므로 반드시 중첩 함수만 Decorator로 사용이 가능하다.
Decorator 사용 예시 만약 유료회원에 한해서 주식정보를 리턴하는 함수가 있다고 가정하자. 일단 먼저 회원의 유료회원 여부를 판단하는 기능과 주식정보를 알려주는 기능으로 나눠서 구현이 가능할 것이다.
def jackpot_stock_information():
return "계시가 내려졌습니다. 삼성전자를 사세요!"
def is_paid_user():
return True #편의를 위해 모든 회원의 유료회원 여부를 True로 Return
그리고 난 다음 회원이 유료 회원이라면 주식정보를 담은 함수를 호출시키면 구현이 가능 할 것이다.
if is_paid_user():
jackpot_stock_information()
하지만 주식 정보를 담은
jackpot_stock_information()
함수가 이곳뿐만 아니라 여러 곳에서 자주 사용한다면 항상is_paid_user()
함수를 호출하여 유료회원 여부를 확인해 줘야 한다. 때문에 이 연결고리를 잊어먹고is_paid_user()
를 통해 확인하지 않고 고급 주식 정보인jackpot_stock_information()
함수를 호출할 확률이 있다. 따라서jackpot_stock_information()
함수를 구현 할때 Decorator로is_paid_user()
를 사용하여 매번jackpot_stock_information()
호출 시 강제로is_paid_user()
가 호출되게 함수를 만들면 해결 할 수 있다.하지만 현재 작성된
is_paid_user()
함수는 중첩 함수가 아니므로 해당 함수를 중첩 함수로 만들어 줘야 한다.
def is_paid_user(func):
user_paid = True # 간단화 하기 위해 무조건 True
def wrapper(*args, **kwargs):
if user_paid:
func() #func() = jackpot_stock_information()
else:
return
return wrapper
이렇게 만든 Decorator를
jackpot_stock_information()
함수에 달아준다.
@is_paid_user #Decorator
def jackpot_stock_information():
return "계시가 내려졌습니다. 삼성전자를 사세요!"
만약 Decorator가 인자를 받는다면 Decorator도 결국 함수이므로 해당 인자를 처리해줄 필요가 있다.
따라서 만약 다음과 같이 Decorator에서 인자를 전달한다면
@name_decorator("정우성")
def greeting():
return "Hello, "
greeting()
로 구현해야 한다. 따라서 Decorator는 다음과 같이 구현이 가능하다.
def name_decorator(name): #@name_decorator에서 전달받은 인자를 처리해줄 함수
def decorator(func): #실제 Decorator
def wrapper(*args, **kwargs): #Decorator 내장 함수
result = func() + name # = greeting() + name_decorator(name)
return result
return wrapper
return decorator